<script setup lang="ts">
import { useSelectorQuery } from '@/hooks/useSelectorQuery';
import useToast from '@/hooks/useToast';
import HomeRequest from '@/request/homeRequest';
import { useAppStore } from '@/store';
import to from '@/utils/to';
import Tools from '@/utils/tools';

interface IProps {
  scroll: boolean;
  merchantId: number;
  collection: boolean;
}

type EmitEvents = {
  // 产品列表加载成功
  (event: 'prodLoadSuccess', payload: { result: boolean }): void;
  // 滚动事件
  (event: 'productScroll', payload: { scrollTop: number; hasInsuHeight: boolean }): void;
};

interface IState {
  categories: IObtainProductCategoriesRes[];
  product: IObtainProductListRes[];
  productLoading: boolean;
  currentCategory: number;
  rightScrollTop: number | string;
  scrollIntoView: string;
  scroll: boolean;
  regDockDate: {
    days: { day: number; timeStamp: number }[];
    selectDay: number;
  };
}

const emits = defineEmits<EmitEvents>();
const props = defineProps<IProps>();
const state = reactive<IState>({ categories: [], product: [], productLoading: true, rightScrollTop: 0, scrollIntoView: '', currentCategory: 0, scroll: props.scroll, regDockDate: { days: [], selectDay: 0 } });
const store = useAppStore();
const { showToast } = useToast();
const { btnInformation, beeperId, beeperParams } = store.$state;
const { eventId } = btnInformation!;
const instace = getCurrentInstance();

onMounted(() => {
  fetchObtainProductCategories();

  // 获得未来7天的日子 挂号对接需要
  if (eventId !== 18) return;
  store.removeShoppingCart(undefined);
  const today = new Date();
  for (let i = 0; i < 7; i++) {
    const futureDate = new Date(today);
    futureDate.setDate(today.getDate() + i);
    state.regDockDate.days.push({ day: futureDate.getDate(), timeStamp: futureDate.getTime() });
  }
  state.regDockDate.selectDay = state.regDockDate.days[0].day;
  store.$patch({ registerData: { ...store.$state.registerData, date: state.regDockDate.selectDay, timeStamp: state.regDockDate.days[0].timeStamp } });
});

watch(
  () => props.scroll,
  (scroll) => {
    state.scroll = scroll;
  },
);

watch(
  () => props.collection,
  (collection) => {
    state.productLoading = true;
    if (collection) {
      state.categories = [];
      state.product = [];
      const params = { businessId: props.merchantId, btnId: btnInformation!.id, beeperId, btnType: btnInformation!.btnType, classifyIds: btnInformation!.classifyIds, queryType: beeperParams.queryType, pageNo: 1, pageSize: 1000, collect: 1 };
      HomeRequest.ObtainCollectedProductList(params)
        .then((res) => {
          state.product = [{ businessClassifyId: 0, businessClassifyName: '', list: res.data.list }];
          state.productLoading = false;
        })
        .catch(() => {
          state.productLoading = false;
        });
    } else {
      fetchObtainProductCategories();
    }
  },
);

watch(
  () => props.merchantId,
  () => {
    fetchObtainProductCategories();
  },
);

// 获得商户分类列表
const fetchObtainProductCategories = () => {
  const params: any = { businessId: props.merchantId, type: 1, btnId: btnInformation!.id, beeperId, btnType: btnInformation!.btnType, classifyIds: btnInformation!.classifyIds, queryType: beeperParams.queryType };
  state.productLoading = true;
  if (state.regDockDate.selectDay) params.strDate = state.regDockDate.selectDay;
  HomeRequest.ObtainProductCategories(params).then((res) => {
    if (res.data && res.data.length > 0) {
      state.categories = res.data.map((item) => {
        return { ...item, name: Tools.extractChineseTextFromHtml(item.name).toString() };
      });
    } else {
      state.categories = [];
    }
    fetchObtainProductList();
  });
};

// 获取产品列表数据
const fetchObtainProductList = async () => {
  const params: any = {
    businessId: props.merchantId,
    type: 1,
    btnId: btnInformation!.id,
    beeperId,
    btnType: btnInformation!.btnType,
    classifyIds: btnInformation!.classifyIds,
    queryType: beeperParams.queryType,
    businessClassifyIds: state.categories.map((item) => item.id).toString(),
    hasLoading: true,
  };
  if (state.regDockDate.selectDay) params.strDate = state.regDockDate.selectDay;
  const [err, res] = await to(HomeRequest.ObtainProductList(params));
  if (err) {
    state.productLoading = false;
    emits('prodLoadSuccess', { result: false });
    return;
  }
  if (!res.data) {
    state.productLoading = false;
    showToast('暂无产品数据');
    state.product = [];
    return;
  }
  if (state.categories.length > 0) {
    state.product = res.data as IObtainProductListRes[];
  } else {
    state.product = [{ businessClassifyId: 0, businessClassifyName: '', list: res.data as IProductInformation[] }];
  }
  // 更新购物车中关于售卖时间的数据
  store.updateShoppingCartHours(Tools.flatProductData(state.product));
  state.productLoading = false;
  emits('prodLoadSuccess', { result: true });
  setTimeout(() => {
    useSelectorQuery('#product-scroll-view', instace).then(async (res) => {
      const productHeights = await obtainProductHeights();
      if (productHeights.reduce((total, num) => total + num, 0) < res.height!) {
        emits('productScroll', { scrollTop: 0, hasInsuHeight: true });
      } else {
        emits('productScroll', { hasInsuHeight: false, scrollTop: 0 });
      }
    });
  }, 200);
};

// 处理左侧分类点击事件
const handleCategoriesTap = async (index: number) => {
  state.scroll = true;
  state.currentCategory = index;
  state.scrollIntoView = `left-${index}`;
  state.rightScrollTop = await obtainRightScrollTop(index);
  state.scroll = false;
};

// 获取右侧产品列表滚动位置
const obtainRightScrollTop = async (index: number) => {
  const productHeights = await obtainProductHeights();
  return index === 0 ? 0 : productHeights[index - 1];
};

// 计算每个分类在右侧的高度累加值
const obtainProductHeights = () => {
  return new Promise<number[]>((resolve, reject) => {
    const query = uni.createSelectorQuery().in(instace!.proxy);
    const heights: number[] = [];
    query
      .selectAll('.product-group')
      .boundingClientRect((res) => {
        let totalHeight = 0;
        if (Array.isArray(res)) {
          res.forEach((item) => {
            totalHeight += item.height ? item.height + 12 : 0;
            heights.push(totalHeight);
          });
          resolve(heights as number[]);
        } else {
          reject(heights);
        }
      })
      .exec();
  });
};

// 产品列表滚动事件
const handleProductScroll = async (e: any) => {
  const scrollTop = e.detail.scrollTop;
  emits('productScroll', { scrollTop, hasInsuHeight: false });
  // 根据滚动位置动态计算当前分类
  let currentCategory = 0;
  const productHeights = await obtainProductHeights();
  for (let i = 0; i < productHeights.length; i++) {
    if (scrollTop < productHeights[i]) {
      currentCategory = i;
      break;
    }
  }
  state.currentCategory = currentCategory;
  state.scrollIntoView = `left-${currentCategory}`;
};

// 日期是今天 or 明天 or 后天
const formatRelativeDay = (day: number) => {
  const today = new Date();
  const todayDay = today.getDate();
  if (day === todayDay) {
    return '今天';
  } else if (day === todayDay + 1) {
    return '明天';
  } else if (day === todayDay + 2) {
    return '后天';
  } else {
    return `${day}号`;
  }
};

// 点击日期选择
const handleRegDockDateClick = (days: { day: number; timeStamp: number }) => {
  state.regDockDate.selectDay = days.day;
  store.$patch({ registerData: { ...store.$state.registerData, date: days.day, timeStamp: days.timeStamp } });
  fetchObtainProductCategories();
};
</script>

<template>
  <view class="w-screen" :style="{ height: eventId === 18 ? `calc(100% - 54px - 52px)` : `calc(100% - 54px)` }" v-if="!state.productLoading">
    <scroll-view scroll-x class="w-full c-pd whitespace-nowrap" v-if="eventId === 18">
      <view class="py-4px px-8px c-br mr-12px inline-block" :class="item.day === state.regDockDate.selectDay ? 'c-bg-sec text-white' : 'bg-white'" v-for="item in state.regDockDate.days" :key="item.day" @click="handleRegDockDateClick(item)">{{ formatRelativeDay(item.day) }}</view>
    </scroll-view>
    <view class="flex h-full w-full">
      <scroll-view v-if="state.categories.length > 1" :scroll-into-view="state.scrollIntoView" enhanced :show-scrollbar="false" class="overflow-hidden h-full w-80px" :scroll-y="state.scroll">
        <view
          class="w-80px h-50px p-8px flex justify-center items-center box-border c-text-color-grey"
          :class="state.currentCategory === index ? 'bg-white c-color-sec' : ''"
          v-for="(item, index) in state.categories"
          :key="item.id"
          :id="`left-${index}`"
          @click="handleCategoriesTap(index)"
        >
          <text class="c-text-12 c-text-ellipsis-2 text-align-center">{{ item.name }}</text>
        </view>
      </scroll-view>
      <scroll-view enhanced :scroll-top="state.rightScrollTop" :show-scrollbar="false" id="product-scroll-view" class="overflow-hidden h-full flex-1 box-border bg-white" :scroll-y="state.scroll" @scroll="handleProductScroll">
        <view v-for="(item, index) in state.product" :key="item.businessClassifyId || index" class="product-group flex-1" :id="`group-${index}`">
          <view v-if="item.businessClassifyName && state.product.length > 1" class="p-8px box-border">
            <van-divider contentPosition="left">
              <text class="fw-bold c-text-16">{{ Tools.extractChineseTextFromHtml(item.businessClassifyName).toString() }}</text>
            </van-divider>
          </view>
          <template v-if="item.list.length > 0">
            <Product v-for="_item in item.list" :key="_item.id" :data="_item" :path="'merchant'" styles="list" />
            <view class="h-60px overflow-hidden" v-if="index === state.product.length - 1"><van-divider contentPosition="center">没有更多了</van-divider></view>
          </template>
          <van-empty v-else description="暂无收藏产品" />
        </view>
        <van-empty v-if="state.product.length === 0" description="暂无数据" />
      </scroll-view>
    </view>
  </view>
  <view v-else class="flex bg-white justify-center items-center" :style="{ height: 'calc(100% - 54px)' }">
    <van-loading vertical type="spinner" :color="'#ffc300'"><text class="c-color">加载中...</text></van-loading>
  </view>
</template>
